import os, logging, cgi, re
from urllib import quote
import wsgiref.handlers
from wsgiref.util import application_uri, request_uri

from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import users
from google.appengine.ext.webapp import template
from werkzeug import BaseRequest as Request
from werkzeug import BaseResponse as Response
import genshi.builder as bldr
from genshi.core import START, Stream

from urlminer import Resource, redirect 
import model
from wikiparser import text2html
import toc

class MyResource(Resource):

    def index(self, environ, start_response):
        self.request = Request(environ)
        self.user = users.get_current_user()
        if self.user:
            login_url = cgi.escape(users.create_logout_url(request_uri(environ)))
            url_linktext = 'logout'
        else:
            login_url = cgi.escape(users.create_login_url(request_uri(environ)))
            url_linktext = 'login'
        self.template_vars = {'user':self.user, 'url_linktext':url_linktext, 'login_url':login_url }
        return super(MyResource,self).index(environ, start_response)
    
    def render(self,templ, template_values=None, status=None):
        if template_values is None:
            template_values = {}
        template_values.setdefault('self',self)
        template_values.setdefault('query_args',self.request.args)
        template_values.update(self.template_vars)
        path = os.path.join(os.path.dirname(__file__), 'templates',templ)
        response = Response(template.render(path, template_values),
                            mimetype='text/html', status=status)
        return response

class Preview(MyResource):
    pattern = 'preview'

    def POST(self, environ, start_response):
        self.record = model.Page.get_by_key_name('-'+self.request.values['page_name'])
        if not self.record:
            logging.info('New Page Preview: '+ self.request.values['page_name']
                         + '\n' + self.request.values['text'].rstrip().replace('\r',''))
            env={'wiki.page':None,
                                                              'wiki.metadata_page':None,
                                                              'wiki.recurse' : set(),
                                                              'wiki.parser': text2html,
                                                                                    }
            stream = text2html.generate(self.request.values['text'].rstrip(),environ=env)
            if 'toc' in env:
                stream = Stream(list(stream))
                stream = stream.filter(toc.Replacer('toc', stream.filter(toc.TOCMaker(env['toc']))))            
        else:
            logging.info('Preview: '+ self.record.name + '\n' + self.request.values['text'].rstrip().replace('\r',''))
            env={'wiki.page':self.record,
                                                              'wiki.metadata_page':self.record,
                                                              'wiki.recurse' : set(),
                                                              'wiki.parser': text2html,
                                                                                    }
            stream = text2html.generate(self.request.values['text'].rstrip(),environ=env)
            if 'toc' in env:
                stream = Stream(list(stream))
                stream = stream.filter(toc.Replacer('toc', stream.filter(toc.TOCMaker(env['toc']))))

        response = Response(stream.render(method='xhtml', strip_whitespace=False, encoding='utf-8')
                            ,mimetype='text/html',status=200)
        return response(environ, start_response)


class Page(MyResource):
    pattern = '.+'

    def GET(self, environ, start_response):
        self.record = model.Page.get_by_key_name('-'+self.path_arg)
        if not self.record:
            response = self.render('no_page.html',status=404)
        elif self.record.viewers and not self.user:
            response = Response("Access to this page is restricted.",mimetype='text/plain',
                                status=403)
        elif self.record.viewers and self.user not in self.record.viewers:
            response = Response("You do not have permission to view this page.",mimetype='text/plain',
                                status=403)
        else:
            env = {'wiki.page':self.record,
                   'wiki.metadata_page':self.record,
                   'wiki.recurse' : set(),
                   'wiki.parser': text2html,
                   }

            stream = text2html.generate(self.record.body.value,environ=env)
            if 'toc' in env:
                stream = Stream(list(stream))
                stream = stream.filter(toc.Replacer('toc', stream.filter(toc.TOCMaker(env['toc']))))
                
            template_values = {
          'page' : self.record,
          'page_name' : cgi.escape(self.record.name),
          'rendered_text':stream.render(method='xhtml', strip_whitespace=False, encoding='utf-8'),
          'action':"/pages/" + quote(self.record.name),
          'editor_class' : 'invisible',
          'viewers': self.record.viewers_list,
          }
            response = self.render('page.html',template_values)

        return response(environ, start_response)

    def POST(self, environ, start_response):
        self.record = model.Page.get_by_key_name('-'+self.path_arg)
        if not self.record:
            response = self.render('no_page.html',status=404)
        elif self.request.values.get('cancel'):
            response = redirect('/pages/' + quote(self.record.name), status=303)
        elif self.record.viewers and not self.user:
            response = Response("Access to this page is restricted.",mimetype='text/plain',
                                status=401)
        elif self.record.viewers and self.user not in self.record.viewers:
            response = Response("You do not have permission to edit this page.",mimetype='text/plain',
                                status=403)
        else:
            if self.user and self.request.values['viewers'].strip():
                viewers = [users.User(x) for x in self.request.values['viewers'].split()]
                if self.user not in viewers:
                    viewers.append(self.user)
            else:
                viewers = []
            self.record.update(self.request.values['text'].rstrip(),viewers)
            logging.info('Page: '+ self.record.name + '\n' + self.record.body.value.replace('\r',''))
            #self.record.put()
            response = redirect('/pages/' + quote(self.record.name), status=303)
        return response(environ, start_response)


class Pages(MyResource):
    children = [Page]
    pattern = re.compile('pages',re.I)

    def GET(self, environ, start_response):

        page_name = self.request.values.get('page_name')
        if not page_name:
            if self.user:
                pages = model.Page.all().order('name').fetch(1000)
            else:
                pages = model.Page.all().filter('ispublic =', True).fetch(1000)
            tmpl = 'pages.html'
            template_values = {'pages':pages,}
        else:
            page_name = page_name.strip()
            record = model.Page.get_by_key_name('-'+page_name)
            if record:
                response = redirect('/pages/' + quote(record.name), status=301)
                return response(environ, start_response)
            else:
                editor_class = 'visible'
                tmpl = 'page.html'
                template_values = {
                'editor_class': editor_class,
                'page_name' : cgi.escape(page_name) if page_name else None,
                'rendered_text':"<p>Adding a page named %s.</p>" % cgi.escape(page_name),
                'action':'/pages',
                'viewers': self.user.email()
                }
        response = self.render(tmpl,template_values)
        return response(environ, start_response)


    def POST(self, environ, start_response):

        record = model.Page.get_by_key_name('-'+self.request.values['page_name'])

        if self.request.values.get('cancel'):
            response = redirect('/pages' , status=303)

        elif not self.user:
            response = Response("You need to be logged in to create new pages.",mimetype='text/plain',
                                status=401)
        elif record:
            response = Response("That page already exists.",mimetype='text/plain',
                                status=403)
            
        elif self.request.values['page_name'].count('/'):
            response = Response("Page names cannot contain the '/' character.",mimetype='text/plain',
                                status=403)
        else:
            if self.request.values['viewers']:
                viewers = [users.User(x) for x in self.request.values['viewers'].split()]
                if self.user not in viewers:
                    viewers.append(self.user)
            else:
                viewers = []
            model.Page.create(self.request.values['page_name'],self.request.values['text'],viewers)

            logging.info('Page: '+ self.request.values['page_name'] + '\n' + self.request.values['text'].replace('\r',''))
            response = redirect('/pages/' + quote(self.request.values['page_name']), status=303)
        return response(environ, start_response)
           
class Root(Resource):
    children = [Pages, Preview]
    
    def GET(self,environ, start_response):
        location = application_uri(environ).rstrip('/') + '/pages'
        if environ.get('QUERY_STRING'):
            location += '?' + environ['QUERY_STRING']
        response = redirect(location, status=302)
        return response(environ, start_response)

def main():
    #logging.getLogger().setLevel(logging.DEBUG)
    application = Root()
    run_wsgi_app(application) 

if __name__ == "__main__":
  main()
